package pl.streamsoft.currencyApp.services;

import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

import javax.naming.OperationNotSupportedException;

import pl.streamsoft.currencyApp.model.Currency;
import pl.streamsoft.currencyApp.parser.XMLCurrencyParser;
import pl.streamsoft.currencyApp.stream.UrlStream;

public class WebCurrencyService implements ICurrencyService {

	private final String nbpServerUrl = "http://www.nbp.pl/kursy/xml/";
	private final Map<String, String> replaceableCurrencyFileName = new LinkedHashMap<String, String>();
	private final static List<Currency> emptyList = Collections.unmodifiableList(new ArrayList<Currency>());
	private boolean isDirFileDownloaded = false;
	private final XMLCurrencyParser xmlParser = new XMLCurrencyParser();
	private final DateFormat shortDateFormatter = new SimpleDateFormat("yyMMdd");
	
	private boolean updateDirFile() {
		try{
			
			Scanner scanner = new Scanner(new UrlStream(nbpServerUrl + "dir.txt").getInputStream());
			while(scanner.hasNextLine()){
				
				String filename = scanner.nextLine();
				
	            if (filename.charAt(0) == 'a') {
	            	replaceableCurrencyFileName.put(filename.substring(5), filename);
	            }
	        }
	       
			scanner.close();
	        return (isDirFileDownloaded = true);
	        
		} catch(Exception e){
			//dir.txt file can't be download
			return false;
		}
    }
	
	public List<String> getPublicatedFileNamesBetween(Date fromDate, Date toDate){
		
		if(!isDirFileDownloaded && !updateDirFile()){ return Collections.EMPTY_LIST; }
		
		List<String> filenames = new ArrayList<String>();
		
		Calendar calendar = Calendar.getInstance();  
		calendar.setTime(fromDate);  
		
		String shortDate;
				
		while(!calendar.getTime().after(toDate)){
			
			shortDate = shortDateFormatter.format(calendar.getTime());
			
			if(replaceableCurrencyFileName.containsKey(shortDate)){ 
				filenames.add(replaceableCurrencyFileName.get(shortDate)); 
			}
			
			calendar.add(Calendar.DATE, 1);
		}		
		return filenames;
	}

	@Override
	public Collection<Currency> getCurrencies(Date dateOfPublication) {
		
		if(!isDirFileDownloaded && !updateDirFile()){ return emptyList; }
				
		if(replaceableCurrencyFileName.containsKey(shortDateFormatter.format(dateOfPublication))){
			return xmlParser.getListOfCurrencies(new UrlStream(nbpServerUrl + replaceableCurrencyFileName.get(shortDateFormatter.format(dateOfPublication)) + ".xml"));
		}
		
		return emptyList;
	}

	@Override
	public Collection<Currency> getCurrenciesByValue(Date dateOfPublication, BigDecimal minValue) {
		List<Currency> selectedCurrencies = new ArrayList<Currency>();
		for(Currency currency : getCurrencies(dateOfPublication)){
			if(currency.getCurrencyValue().getAverageRate().compareTo(minValue) != -1){ 
				selectedCurrencies.add(currency);
			}
		}
		return selectedCurrencies;
	}

	@Override
	public Currency getCurrencyByCode(Date dateOfPublication, String codeName) {		
		for(Currency currency : getCurrencies(dateOfPublication)){
			if(currency.getCurrencyInfo().getCode().equalsIgnoreCase(codeName)){ return currency; }
		}
		
		return null;
	}

	@Override
	public Currency getCurrencyByName(Date dateOfPublication, String name) {
		for(Currency currency : getCurrencies(dateOfPublication)){
			if(currency.getCurrencyInfo().getName().equalsIgnoreCase(name)){ return currency; }
		}
		
		return null;
	}

	@Override
	public Collection<Currency> getLatestCurrencies() {
		return xmlParser.getListOfCurrencies(new UrlStream(nbpServerUrl + "LastA.xml"));
	}

	@Override
	public Collection<Currency> getCurrenciesByKeyWord(Date dateOfPublication, String keyWord) {
		List<Currency> selectedCurrencies = new ArrayList<Currency>();
		for(Currency currency : getCurrencies(dateOfPublication)){
			if(currency.getCurrencyInfo().getCode().contains(keyWord) || currency.getCurrencyInfo().getName().contains(keyWord)){ selectedCurrencies.add(currency); }
		}
		return selectedCurrencies;
	}
	
	@Override
	public Collection<Currency> getCurrencies(Date fromDate, Date toDate) {
		List<Currency> currencies = new ArrayList<Currency>();
		for(String filename : getPublicatedFileNamesBetween(fromDate, toDate)){
			currencies.addAll(xmlParser.getListOfCurrencies(new UrlStream(nbpServerUrl + filename + ".xml")));
		}
		return currencies;
	}

	@Override
	public Collection<Currency> getCurrenciesByValue(Date dateOfPublication, BigDecimal minValue, BigDecimal maxValue) {
		List<Currency> currencies = new ArrayList<Currency>();
		BigDecimal val;
		
		for(Currency currency : getCurrencies(dateOfPublication)){
			val = currency.getCurrencyValue().getAverageRate();
			if((minValue.compareTo(val) > 0) || (maxValue.compareTo(val) < 0)) { continue; }
			currencies.add(currency);
		}
		return currencies;
	}
	
	//not supported
	
	@Override
	public void remove(Currency currency) {
		throw new RuntimeException(new OperationNotSupportedException());
	}

	@Override
	public void update(Currency currency) {
		throw new RuntimeException(new OperationNotSupportedException());		
	}

	@Override
	public void addCurrency(Currency currency) {
		throw new RuntimeException(new OperationNotSupportedException());
	}
	
	@Override
	public void addCurrency(Collection<Currency> currencies) {
		throw new RuntimeException(new OperationNotSupportedException());
	}
}
